<template>
  <div class="file-upload-container">
    <!-- 上传区域 -->
    <el-upload
      class="upload-demo"
      drag
      action="/"
      multiple
      :auto-upload="false"
      :on-change="handleFileChange"
      :on-remove="handleRemoveFile"
      :file-list="fileList"
      :limit="10"
    >
      <el-icon class="upload-icon"><upload-filled /></el-icon>
      <div class="upload-text">
        拖拽文件到此处或 <span class="upload-click">点击上传</span>
        <div class="upload-subtext">支持单个文件 ≤ 2GB，10MB以下为小文件直传</div>
      </div>
    </el-upload>

    <!-- 上传按钮 -->
    <el-button 
      type="primary" 
      @click="startUpload" 
      class="upload-btn" 
      :disabled="isUploading"
    >
      {{ isUploading ? '上传中...' : '开始上传' }}
    </el-button>

    <!-- 分片上传进度弹窗 -->
    <el-dialog
      title="大文件上传进度"
      :visible="showChunkProgress"
      :width="isMobile ? '90%' : '500px'"
      :close-on-click-modal="false"
      :show-close="false"
      center
    >
      <div class="chunk-info">
        <div class="file-name">{{ currentChunkFile?.name || '' }}</div>
        <div class="file-size">{{ currentChunkFile?.size | formatSize }}</div>
      </div>
      
      <el-progress
        :percentage="chunkProgress"
        :status="chunkStatus"
        class="chunk-progress"
        text-inside
        stroke-width="16"
      />
      
      <div class="chunk-detail">
        <span>分片：{{ currentChunk }} / {{ totalChunks }}</span>
        <span>速度：{{ uploadSpeed }}</span>
      </div>
      
      <div class="chunk-actions" v-if="chunkStatus === 'exception'">
        <el-button type="primary" size="small" @click="retryChunkUpload">重试</el-button>
        <el-button size="small" @click="closeChunkProgress">取消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
import { ElNotification, ElDialog, ElProgress, ElButton, ElIcon } from "element-plus";
import { UploadFilled } from "@element-plus/icons-vue";
// 只导入你file.ts中已封装好的接口，不额外引入axios
import { 
  secUpload, 
  uploadFiles, // 复用你已封装的单文件上传接口
  initTask, 
  taskInfo, 
  preSignUploadUrl, 
  merge 
} from "@/api/file";
import calculateFileMD5 from "@/utils/md5";
import { calcUploadSpeed, formatFileSize } from "@/utils/upload-helper";
import { useLoginUserStore } from "@/store/user";

// Props：当前路径（用于文件保存位置）
const props = defineProps({
  currentPath: {
    type: String,
    required: true
  }
});

// 全局状态
const { loginUser } = useLoginUserStore();
const accountNo = loginUser?.id || "";
const parentId = localStorage.getItem("parent_id") || "";
const emit = defineEmits(["upload-success", "upload-error", "upload-progress"]);

// 上传队列状态
const fileList = ref([]);
const isUploading = ref(false);
const isMobile = ref(false);

// 分片上传状态（进度弹窗用）
const showChunkProgress = ref(false);
const currentChunkFile = ref(null); // 当前上传的文件对象
const chunkProgress = ref(0);
const chunkStatus = ref(""); // success/exception/''
const currentChunk = ref(0);
const totalChunks = ref(0);
const uploadSpeed = ref("0 KB/s");
const currentTask = ref(null); // 存储当前分片任务（用于重试）

// 辅助变量：速度计算
let lastLoaded = 0;
let lastTime = 0;

// 检测设备类型（用于弹窗适配）
const checkDevice = () => {
  isMobile.value = window.innerWidth <= 768;
};

// 格式化文件大小过滤器
const formatSizeFilter = (value) => {
  return formatFileSize(value);
};

// 1. 处理文件添加
const handleFileChange = (file, uploadFiles) => {
  // 初始化文件状态
  file.percentage = 0;
  file.status = "ready"; // ready/uploading/success/error
  file.size = file.raw.size; // 存储原始大小（用于显示）
  fileList.value = uploadFiles;
};

// 2. 处理文件移除
const handleRemoveFile = (file) => {
  // 移除时关闭对应进度弹窗
  if (currentChunkFile.value?.uid === file.uid) {
    resetChunkState();
  }
  fileList.value = fileList.value.filter(f => f.uid !== file.uid);
};

// 3. 小文件上传（≤10MB）：完全复用你file.ts中的uploadFiles接口
const uploadSmallFile = async (file) => {
  try {
    // 计算MD5（用于秒传校验和标识）
    const identifier = await calculateFileMD5(file.raw);
    
    // 构建FormData：匹配你uploadFiles接口的API.UploadFile类型要求
    const formData = new FormData();
    formData.append("file", file.raw);
    formData.append("identifier", identifier);
    formData.append("fileName", file.name);
    formData.append("accountNo", accountNo);
    formData.append("parentId", parentId);
    formData.append("fileSize", file.size.toString());

    // 直接调用你file.ts中封装好的uploadFiles接口，传递formData和进度配置
    const response = await uploadFiles(formData, {
      // 给接口传递onUploadProgress配置（你的request工具需支持传递该参数）
      onUploadProgress: (e) => {
        if (e.lengthComputable) {
          const percent = Math.min(Math.ceil((e.loaded / e.total) * 100), 100);
          file.percentage = percent;
          emit("upload-progress", { file, progress: percent });
        }
      }
    });

    // 接口返回逻辑：与你file.ts中uploadFiles的返回格式一致
    if (response.data.code === 0) {
      file.status = "success";
      emit("upload-success", { file, data: response.data });
      ElNotification.success({ title: "上传成功", message: `文件 ${file.name} 已上传` });
      // 从队列移除已完成文件
      fileList.value = fileList.value.filter(f => f.uid !== file.uid);
      return true;
    } else {
      throw new Error(response.data.msg || "小文件上传失败");
    }
  } catch (error) {
    file.status = "error";
    emit("upload-error", { file, error: error.message });
    ElNotification.error({ title: "上传失败", message: `${file.name}：${error.message}` });
    return false;
  }
};

// 4. 分片上传工具：获取预签名URL（复用file.ts的preSignUploadUrl）
const getChunkUploadUrl = async (identifier, partNumber) => {
  // 直接调用你file.ts中封装的preSignUploadUrl，参数匹配API.preSignUploadUrlParams类型
  const res = await preSignUploadUrl({ identifier, partNumber });
  if (res.data.code !== 0 || !res.data.data) {
    throw new Error(`获取分片${partNumber}上传地址失败：${res.data.msg || ""}`);
  }
  return res.data.data;
};

// 5. 分片上传工具：上传单个分片（仅用axios传分片数据，无接口冗余）
const uploadChunk = async (file, identifier, partNumber, chunkSize, finishedSize) => {
  const start = partNumber * chunkSize;
  const end = Math.min(start + chunkSize, file.size);
  const blob = file.raw.slice(start, end);
  const uploadUrl = await getChunkUploadUrl(identifier, partNumber + 1); // 接口partNumber从1开始

  // 分片上传：仅发起PUT请求（无接口封装，因preSignUploadUrl返回的是第三方地址）
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("PUT", uploadUrl);
    xhr.setRequestHeader("Content-Type", "application/octet-stream");
    
    // 分片进度监听
    xhr.upload.addEventListener("progress", (e) => {
      if (e.lengthComputable) {
        // 总进度 =（已完成分片大小 + 当前分片已传大小）/ 总大小
        const currentLoaded = finishedSize + e.loaded;
        const percent = Math.min(Math.ceil((currentLoaded / file.size) * 100), 100);
        
        // 更新速度
        const speedResult = calcUploadSpeed(currentLoaded, lastLoaded, lastTime);
        uploadSpeed.value = speedResult.speedText;
        lastLoaded = speedResult.newLastLoaded;
        lastTime = speedResult.newLastTime;
        
        // 同步进度到弹窗和文件列表
        chunkProgress.value = percent;
        file.percentage = percent;
        emit("upload-progress", { file, progress: percent });
      }
    });

    // 上传完成/失败处理
    xhr.addEventListener("load", () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(end - start); // 返回当前分片实际大小
      } else {
        reject(new Error(`分片${partNumber + 1}上传失败，状态码：${xhr.status}`));
      }
    });
    xhr.addEventListener("error", () => {
      reject(new Error(`分片${partNumber + 1}上传网络错误`));
    });

    xhr.send(blob);
  });
};

// 6. 大文件分片上传（>10MB）：复用file.ts的initTask/taskInfo/merge接口
const uploadLargeFile = async (file) => {
  try {
    // 计算文件MD5
    const identifier = await calculateFileMD5(file.raw);
    
    // 初始化弹窗状态
    currentChunkFile.value = file;
    showChunkProgress.value = true;
    chunkStatus.value = "";
    chunkProgress.value = 0;
    lastLoaded = 0;
    lastTime = 0;

    // 1. 检查是否已有上传任务：复用file.ts的taskInfo接口
    const taskRes = await taskInfo({ identifier });
    let taskRecord;

    if (taskRes.data.code === 0 && taskRes.data.data) {
      // 已有任务：使用现有分片信息（匹配接口返回格式）
      taskRecord = {
        chunkSize: taskRes.data.data.chunkSize,
        chunkNum: taskRes.data.data.chunkNum,
        exitPartList: taskRes.data.data.exitPartList || []
      };
    } else {
      // 2. 新任务：复用file.ts的initTask接口，参数匹配API.ChunkInitTaskRequest类型
      const initRes = await initTask({
        accountNo,
        identifier,
        fileName: file.name,
        totalSize: file.size,
        chunkSize: 5 * 1024 * 1024 // 5MB分片（与你接口定义一致）
      });
      if (initRes.data.code !== 0) {
        throw new Error(`初始化分片任务失败：${initRes.data.msg || ""}`);
      }
      taskRecord = {
        chunkSize: 5 * 1024 * 1024,
        chunkNum: Math.ceil(file.size / (5 * 1024 * 1024)),
        exitPartList: []
      };
    }

    // 存储当前任务（用于重试）
    currentTask.value = { file, identifier, taskRecord };
    totalChunks.value = taskRecord.chunkNum;
    let finishedSize = taskRecord.exitPartList.reduce((sum, part) => sum + Number(part.size), 0);
    
    // 初始化已完成进度
    if (finishedSize > 0) {
      const initPercent = Math.ceil((finishedSize / file.size) * 100);
      chunkProgress.value = initPercent;
      file.percentage = initPercent;
    }

    // 3. 上传未完成的分片
    for (let i = 0; i < taskRecord.chunkNum; i++) {
      // 跳过已上传的分片
      if (taskRecord.exitPartList.some(part => part.partNumber === i + 1)) {
        currentChunk.value = i + 1;
        continue;
      }

      // 上传当前分片
      currentChunk.value = i + 1;
      const chunkSize = await uploadChunk(
        file,
        identifier,
        i, // 前端从0开始计数，接口partNumber从1开始
        taskRecord.chunkSize,
        finishedSize
      );
      finishedSize += chunkSize;
      taskRecord.exitPartList.push({ partNumber: i + 1, size: chunkSize });
    }

    // 4. 合并分片：复用file.ts的merge接口，参数匹配API.FileMergeRequest类型
    const mergeRes = await merge({
      identifier,
      accountNo,
      parentId
    });
    if (mergeRes.data.code !== 0) {
      throw new Error(`文件合并失败：${mergeRes.data.msg || ""}`);
    }

    // 上传成功
    chunkStatus.value = "success";
    chunkProgress.value = 100;
    file.status = "success";
    emit("upload-success", { file, data: mergeRes.data });
    ElNotification.success({ title: "上传成功", message: `文件 ${file.name} 已上传` });
    
    // 延迟关闭弹窗（展示100%状态）
    setTimeout(() => {
      resetChunkState();
      fileList.value = fileList.value.filter(f => f.uid !== file.uid);
    }, 1500);

  } catch (error) {
    chunkStatus.value = "exception";
    file.status = "error";
    emit("upload-error", { file, error: error.message });
    ElNotification.error({ title: "上传失败", message: `${file.name}：${error.message}` });
  }
};

// 7. 单个文件上传入口（自动区分大小）：复用file.ts的secUpload接口
const uploadSingleFile = async (file) => {
  if (file.status === "uploading" || file.status === "success") return;

  file.status = "uploading";
  emit("upload-progress", { file, progress: 0 });

  // 1. 先检查秒传：复用file.ts的secUpload接口，参数匹配API.SecUploadRequest类型
  const identifier = await calculateFileMD5(file.raw);
  const secRes = await secUpload({
    identifier,
    fileName: file.name,
    accountNo,
    parentId
  });

  if (secRes.data.code === 0 && secRes.data.data === true) {
    // 秒传成功
    file.status = "success";
    file.percentage = 100;
    emit("upload-success", { file, data: secRes.data });
    ElNotification.success({ title: "秒传成功", message: `文件 ${file.name} 已存在` });
    fileList.value = fileList.value.filter(f => f.uid !== file.uid);
    return;
  }

  // 2. 区分小文件/大文件
  if (file.size <= 10 * 1024 * 1024) { // 10MB阈值
    await uploadSmallFile(file);
  } else {
    await uploadLargeFile(file);
  }
};

// 8. 批量上传入口
const startUpload = async () => {
  const pendingFiles = fileList.value.filter(f => f.status === "ready");
  if (pendingFiles.length === 0) {
    ElNotification.warning({ title: "提示", message: "请选择待上传文件" });
    return;
  }

  isUploading.value = true;
  // 串行上传（避免并发过多）
  for (const file of pendingFiles) {
    await uploadSingleFile(file);
    // 若当前有分片弹窗，等待弹窗关闭后再继续
    if (showChunkProgress.value) {
      await new Promise(resolve => {
        const checkClose = setInterval(() => {
          if (!showChunkProgress.value) {
            clearInterval(checkClose);
            resolve(null);
          }
        }, 300);
      });
    }
  }
  isUploading.value = false;
};

// 9. 分片上传重试
const retryChunkUpload = async () => {
  const { file } = currentTask.value || {};
  if (file) {
    chunkStatus.value = "";
    await uploadLargeFile(file);
  }
};

// 10. 关闭分片进度弹窗
const closeChunkProgress = () => {
  resetChunkState();
  const { file } = currentTask.value || {};
  if (file) {
    file.status = "error";
  }
};

// 重置分片状态
const resetChunkState = () => {
  showChunkProgress.value = false;
  currentChunkFile.value = null;
  chunkProgress.value = 0;
  chunkStatus.value = "";
  currentChunk.value = 0;
  totalChunks.value = 0;
  uploadSpeed.value = "0 KB/s";
  currentTask.value = null;
};

// 生命周期
onMounted(() => {
  checkDevice();
  window.addEventListener("resize", checkDevice);
});

onBeforeUnmount(() => {
  window.removeEventListener("resize", checkDevice);
  resetChunkState();
});
</script>

<style scoped>
.file-upload-container{width:100%;display:flex;flex-direction:column;align-items:center;gap:16px;padding:16px;box-sizing:border-box;}
.upload-demo{width:100%;border:2px dashed #dcdcdc;border-radius:8px;padding:30px;transition:all .3s ease;box-sizing:border-box;}
.upload-demo:hover{border-color:#409eff;background-color:rgba(64,158,255,.05);}
.upload-icon{font-size:36px;color:#409eff;margin-bottom:12px;display:flex;justify-content:center;}
.upload-text{text-align:center;color:#606266;}
.upload-click{color:#409eff;cursor:pointer;text-decoration:underline;margin:0 4px;}
.upload-subtext{font-size:12px;margin-top:8px;color:#909399;}
.upload-btn{width:120px;height:40px;font-size:16px;transition:all .2s;}
.upload-btn:hover:not(:disabled){transform:scale(1.05);}
.upload-btn:disabled{opacity:.8;cursor:not-allowed;}

/* 分片进度弹窗样式 */
.chunk-info{margin-bottom:16px;}
.file-name{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.file-size{font-size:12px;color:#606266;margin-top:4px;}
.chunk-progress{margin:16px 0;}
.chunk-detail{display:flex;justify-content:space-between;font-size:12px;color:#606266;margin-bottom:20px;}
.chunk-actions{display:flex;justify-content:center;gap:12px;}

/* 响应式 */
@media (max-width:992px){
  .upload-demo{padding:20px;}
  .upload-icon{font-size:30px;}
  .upload-btn{width:100px;height:36px;font-size:14px;}
}
@media (max-width:768px){
  .upload-demo{padding:15px;}
  .upload-icon{font-size:24px;}
  .upload-text{font-size:13px;}
  .upload-btn{width:90px;height:32px;font-size:13px;}
  .chunk-detail{flex-direction:column;gap:4px;}
}
</style>